package com.dji.mobilesdk.vision;

import android.app.ActionBar;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.os.Bundle;
import androidx.annotation.NonNull;
import android.util.Log;
import android.view.TextureView;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
import dji.common.flightcontroller.FlightControllerState;
import dji.common.product.Model;
import dji.sdk.base.BaseProduct;
import dji.sdk.camera.Camera;
import dji.sdk.camera.VideoFeeder;
import dji.sdk.codec.DJICodecManager;
import dji.sdk.flightcontroller.FlightController;

import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.aruco.Aruco;
import org.opencv.aruco.Dictionary;
import org.opencv.core.Mat;

public class MainActivity extends Activity implements TextureView.SurfaceTextureListener {
    private static final String TAG = "MainActivity";

    private Dictionary dictionary;
    private TextView isFlyingTextView;
    private TextureView videostreamPreview;
    private TextureView modifiedVideostreamPreview;

    protected VideoFeeder.VideoDataListener mReceivedVideoDataListener = null;
    protected DJICodecManager mCodecManager = null;

    private DroneHelper droneHelper;
    private OpenCVHelper openCVHelper;
    private ActionBar actionBar;

    private Canvas canvas;
    private Bitmap edgeBitmap;



    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.activity_main);
        actionBar = getActionBar();

        initUI();
        droneHelper = new DroneHelper();
        openCVHelper = new OpenCVHelper();

        //相机实时接收原始H264视频数据的回调
        mReceivedVideoDataListener = new VideoFeeder.VideoDataListener() {
            @Override
            public void onReceive(byte[] videoBuffer, int size) {
                if (mCodecManager != null) {
                    mCodecManager.sendDataToDecoder(videoBuffer, size);
                }
            }
        };
        initFlightController();
    }

    @Override
    public void onPause() {
        uninitPreviewer();
        super.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();

        boolean result =  OpenCVLoader.initDebug();
        Log.d(TAG, "Loading OpenCV Libraries：" + result);

        initPreviewer();
    }

    public void onDestroy() {
        if (mCodecManager != null) {
            mCodecManager.cleanSurface();
            mCodecManager.destroyCodec();
            mCodecManager = null;
        }
        super.onDestroy();
    }


    private void initUI() {
        isFlyingTextView = findViewById(R.id.is_flying_text_view);
        videostreamPreview = findViewById(R.id.livestream_preview_ttv);
        modifiedVideostreamPreview = findViewById(R.id.modified_livestream_preview_ttv);
        if (videostreamPreview != null) {
            videostreamPreview.setSurfaceTextureListener(this);
        }
    }

    private void initPreviewer() {
        dictionary = Aruco.getPredefinedDictionary(Aruco.DICT_4X4_50);
        final BaseProduct product = DJIVisionApplication.getProductInstance();
        Log.d(TAG,
              "notifyStatusChange: " + (product == null
                                        ? "Disconnect"
                                        : (product.getModel() == null ? "null model" : product.getModel().name())));
        if (product != null && product.isConnected() && product.getModel() != null) {
            updateTitle(product.getModel().name() + " Connected ");
        } else {
            updateTitle("Disconnected");
        }

        if (null == product || !product.isConnected()) {
            showToast("Disconnected");
            return;
        }
        if (videostreamPreview != null) {
            videostreamPreview.setSurfaceTextureListener(this);
        }
        if (!product.getModel().equals(Model.UNKNOWN_AIRCRAFT)) {
            VideoFeeder.VideoFeed videoFeed = VideoFeeder.getInstance().getPrimaryVideoFeed();
            if (videoFeed != null) {
                videoFeed.addVideoDataListener(mReceivedVideoDataListener);
            }
        }
    }

    private void uninitPreviewer() {
        Camera camera = DJIVisionApplication.getProductInstance().getCamera();
        if (camera != null) {
            // Reset the callback
            VideoFeeder.getInstance().getPrimaryVideoFeed().removeVideoDataListener(mReceivedVideoDataListener);
        }
    }

    private void showToast(final String message) {
        runOnUiThread(new Runnable() {
            public void run() {
                Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void updateTitle(String message) {
        if (actionBar != null) {
            actionBar.setTitle(message);
        }
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
        if (mCodecManager == null) {
            mCodecManager = new DJICodecManager(getApplicationContext(), surface, width, height);
        }
    }
    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
        //Do nothing
    }
    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
        if (mCodecManager != null) {
            mCodecManager.cleanSurface();
        }
        return false;
    }
    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
        mCodecManager.getBitmap(new DJICodecManager.OnGetBitmapListener() {
            @Override
            public void onGetBitmap(Bitmap bitmap) {
                drawProcessedVideo(bitmap);
            }
        });
    }

    public void drawProcessedVideo(Bitmap bitmap) {
        if (bitmap != null) {
            Mat source = new Mat();
            Utils.bitmapToMat(bitmap, source);
            Mat processed = openCVHelper.detectArucoTag(source, dictionary, droneHelper);

            edgeBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);

            Utils.matToBitmap(processed, edgeBitmap);
            canvas = modifiedVideostreamPreview.lockCanvas();
            if (canvas != null) {
                canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
                if (BuildConfig.DEBUG) {
                    canvas.drawBitmap(edgeBitmap,
                                      new Rect(0, 0, edgeBitmap.getWidth(), edgeBitmap.getHeight()),
                                      new Rect((canvas.getWidth() - edgeBitmap.getWidth()) / 2,
                                               (canvas.getHeight() - edgeBitmap.getHeight()) / 2,
                                               (canvas.getWidth() - edgeBitmap.getWidth()) / 2 + edgeBitmap.getWidth(),
                                               (canvas.getHeight() - edgeBitmap.getHeight()) / 2
                                                   + edgeBitmap.getHeight()),
                                      null);
                }

                modifiedVideostreamPreview.unlockCanvasAndPost(canvas);
                canvas.setBitmap(null);
                canvas = null;
                edgeBitmap.recycle();
                edgeBitmap = null;
            }
        }
    }

    public void onClickGimbalButton(View view) {
        droneHelper.toggleGimbal();
    }

    public void onClickTakeoffButton(View view) {
        droneHelper.takeoff();
    }

    public void onClickLandButton(View view) {
        droneHelper.land();
    }

    private void initFlightController() {
        FlightController flightController = droneHelper.fetchFlightController();
        if (flightController != null) {
            flightController.setStateCallback(new FlightControllerState.Callback() {
                @Override
                public void onUpdate(@NonNull FlightControllerState flightControllerState) {
                    setCurrentState(flightControllerState);
                }
            });
        }
    }

    public void setCurrentState(final FlightControllerState state) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if(state.isFlying()) {
                    isFlyingTextView.setText(getResources().getString(R.string.flying));
                } else {
                    isFlyingTextView.setText(getResources().getString(R.string.landed));
                }

            }
        });
    }
}
